using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using ICSharpCode.NRefactory.PrettyPrinter;
using ICSharpCode.NRefactory;

namespace AstHelpers
{
	public abstract class CodeGeneratorTask : Task
	{
		protected abstract ICodeGenerator CreateOutputVisitor();
		protected abstract String GeneratedFileSuffix();

		public ITaskItem[] Inputs
		{
			get;
			set;
		}
		[Output]
		public ITaskItem[] Outputs
		{
			get;
			set;
		}
		[Required]
		public String OutputDir
		{
			get;
			set;
		}



		public override bool Execute()
		{
			if(!Directory.Exists(OutputDir))
			{
				Directory.CreateDirectory(OutputDir);
			}
			List<TaskItem> outputs = new List<TaskItem>();
			foreach(var file in Inputs.Select(item => item.ItemSpec))
			{
				FileInfo fileInfo = new FileInfo(file);
				string generatedFile = Path.Combine(OutputDir, fileInfo.Name + GeneratedFileSuffix());
				FileInfo generatedFileInfo = new FileInfo(generatedFile);

				if(File.Exists(generatedFile))
				{
					if(generatedFileInfo.LastWriteTime >= fileInfo.LastWriteTime)
					{
						outputs.Add(new TaskItem(generatedFile));
						continue; //The file has not been modified since the last time, so skip
					}
				}

				var generator = CreateOutputVisitor();
				var parser = ParserFactory.CreateParser(file);
				parser.Parse();
				if(parser.Errors.Count > 0)
					continue; //Skip, Microsoft compiler will catch this problem
				parser.CompilationUnit.AcceptVisitor(generator, null);

				var codeGenerator = GetOutputVisitor(file);
				if(codeGenerator == null)
				{
					Log.LogError("the language of " + file + " is not supported by the generator");
					return false;
				}
				generator.CompilationUnit.AcceptVisitor(codeGenerator, null);
				if(!File.Exists(generatedFile))
					File.Create(generatedFile).Close();
				File.WriteAllText(generatedFile, codeGenerator.Text);

				outputs.Add(new TaskItem(generatedFile));
			}
			Outputs = outputs.ToArray();
			return true;
		}

		private IOutputAstVisitor GetOutputVisitor(string file)
		{
			if(file.EndsWith(".cs"))
				return new CSharpOutputVisitor();
			else if(file.EndsWith(".vb"))
				return new VBNetOutputVisitor();
			else
				return null;
		}
	}

}
